from typing import Optional
from django.contrib.auth.models import AnonymousUser
from django.db import connection

from rest_framework.views import APIView
from rest_framework_simplejwt.exceptions import TokenError
from rest_framework.exceptions import AuthenticationFailed

from .models import User


class TenantMiddleware:

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        return self.get_response(request)

    def __authenticate_request(self, request, view_func) -> Optional[User]:
        # DRF saves the class of the view function as the .cls property
        view_class = view_func.cls
        try:
            # We need to instantiate the class
            view = view_class()
            # And give it an action_map. It's not relevant for us, but otherwise it errors.
            view.action_map = {}
            # Here's our fully formed and authenticated (or not, depending on credentials) request
            drf_request = view.initialize_request(request)
        except (AttributeError, TypeError):
            # Can't initialize the request from this view. Fallback to using default permission classes
            drf_request = APIView().initialize_request(request)

        try:
            return drf_request.user
        except (AuthenticationFailed, TokenError):
            return AnonymousUser()

    def process_view(self, request, view_func, view_args, view_kwargs):
        user = self.__authenticate_request(request, view_func)

        if isinstance(user, User):
            target_schema = user.tenant.schema_name
            connection.set_schema(target_schema)

        return None
